<template>
  <view class="content">
    <view class="one" @click="openBlue">初始化蓝牙</view>
    <view class="one" @click="searchBlue">开始搜索蓝牙</view>
    <view class="one" @click="createBlue">连接蓝牙</view>
    <view class="one" @click="getBLEDeviceServices">获取设备特征</view>
    <view class="one" @click="writeBLECharacteristicValue">写入</view>
    <view class="one" @click="readBLECharacteristicValue">读取</view>
    <view class="one">
      <input type="text" placeholder="输入" v-model="txt" />
    </view>
  </view>
</template>
<script>
// import encoding from '../../static/encoding.js'
export default {
  data() {
    return {
      device: [], //搜索到的设备
      deviceId: "", //设备id
      serverList: [], //服务
      serviceId: "",
      characteristics: [], //特征值
      characteristicId: "", //特征值uuid
      writeId: "", //可写
      readId: "", //可读·
      txt: "",
    };
  },
  mounted() {},
  methods: {
    openBlue() {
      //初始化蓝牙
      uni.openBluetoothAdapter({
        success(res) {
          //console.log('初始化蓝牙成功',res)
          uni.getBluetoothAdapterState({
            //检测蓝牙是否打开 //获取本机蓝牙适配器状态
            //蓝牙的匹配状态
            success: (res1) => {
              console.log(res1, "“本机设备的蓝牙已打开”");
            },
            fail(error) {
              uni.showToast({
                icon: "none",
                title: "查看手机蓝牙(安卓蓝牙定位)是否打开",
              });
            },
          });
        },
        fail(err) {
          console.log("初始化蓝牙失败");
          uni.showToast({
            title: "请打开蓝牙",
            icon: "error",
          });
          console.error(err);
        },
      });
    },
    searchBlue() {
      //搜索监听蓝牙
      var that = this;
      uni.startBluetoothDevicesDiscovery({
        allowDuplicatesKey: true, //允许重复上报同一个设备
        success: (res) => {
          console.log("搜索蓝牙成功 success", res);
          //监听寻找到新设备的事件
          that.onBluetoothDeviceFound();
        },
        fail(err) {
          console.log("搜索失败");
          console.error(err);
        },
      });
    },
    onBluetoothDeviceFound() {
      // 获取设备列表
      uni.onBluetoothDeviceFound((res) => {
        console.log(res.devices, "搜索完成所有的设备列表");

        var that = this;
        that.device = res.devices; //搜索到的设备
        //that.deviceId = res.devices[0].deviceId
        res.devices.forEach((item) => {
          //搜索指定设备
          if (item.name == "HC-08") {
            //REGLOCK_4ed8
            that.deviceId = item.deviceId;
            console.log("deviceId:", item.deviceId);
          }
        });
        //获取到指定设备之后  停止搜索
        uni.stopBluetoothDevicesDiscovery({
          success(res) {
            console.log("停止搜索蓝牙", res);
          },
        });
      });
    },
    createBlue() {
      //连接蓝牙
      let that = this;
      console.log(that.deviceId, "========");

      uni.createBLEConnection({
        deviceId: that.deviceId,
        success(res) {
          console.log(res, "连接成功");

          //连接成功之后  停止搜索
          uni.stopBluetoothDevicesDiscovery({
            success(res) {
              console.log("停止搜索蓝牙", res);
            },
          });

          uni.getConnectedBluetoothDevices({
            //已连接
            success(res) {
              console.log(res.devices, "已连接过的设备");
            },
          });
        },
        fail(res) {
          uni.showToast({
            title: "蓝牙连接失败",
            icon: "none",
          });
          //uni.hideLoading()
        },
        computed(res) {
          //设备获取完成之后  停止搜索
          uni.stopBluetoothDevicesDiscovery({
            success(res) {
              console.log("停止搜索蓝牙", res);
            },
          });
        },
      });
    },
    //获取蓝牙设备所有服务(service)。
    getBLEDeviceServices() {
      const _this = this;
      console.log(_this.deviceId);
      setTimeout(() => {
        uni.getBLEDeviceServices({
          // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
          deviceId: _this.deviceId,
          success: (res) => {
            //此时需要循环遍历每个serviceId获取到特征值，但是在厂商中只有6e4开头获取到的特征值才能操作蓝牙
            console.log(
              "获取蓝牙设备所有服务serviceId:",
              JSON.stringify(res.services)
            );
            _this.serverList = res.services;

            console.log(JSON.stringify(res.services[2].uuid));

            _this.serviceId = res.services[2].uuid; //选择支持的uuid
            _this.getBLEDeviceCharacteristics(); //获取设备特征
          },
          fail: (res) => {
            console.log(res);
          },
        });
      }, 1000);
    },
    getBLEDeviceCharacteristics() {
      //获取设备特征
      var that = this;
      console.log("进入特征");
      setTimeout(() => {
        uni.getBLEDeviceCharacteristics({
          // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
          deviceId: that.deviceId,
          // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
          serviceId: that.serviceId,
          success: (res) => {
            console.log(res, "特征getBLEDeviceCharacteristics");
            //	that.characteristics = res.characteristics

            //	that.characteristicId = res.characteristics[0].uuid
            for (var i = 0; i < res.characteristics.length; i++) {
              if (res.characteristics[i].properties.notify === true) {
                //可通知
                that.characteristics = res.characteristics[i];
                that.characteristicId = res.characteristics[i].uuid;
              }

              if (res.characteristics[i].properties.write === true) {
                //可写 notify也要true
                that.characteristics = res.characteristics[i];
                that.writeId = res.characteristics[i].uuid;
              }
              if (res.characteristics[i].properties.read === true) {
                //可读
                that.characteristics = res.characteristics[i];
                that.readId = res.characteristics[i].uuid;
              }
            }

            setTimeout(() => {
              that.notifyBLECharacteristicValueChange();
            }, 3000);
          },
          fail: (res) => {
            console.log(res);
          },
        });
      }, 1000);
    },
    // 启用 notify 功能
    notifyBLECharacteristicValueChange() {
      const _this = this;
      uni.notifyBLECharacteristicValueChange({
        state: true,
        deviceId: _this.deviceId,
        serviceId: _this.serviceId,
        characteristicId: _this.characteristicId,
        success: function (res) {
          console.log("启用notify成功", res);

          setTimeout(() => {
            //接收消息的方法
            _this.onBLECharacteristicValueChange();
          }, 2000);
        },
        fail: function (res) {
          console.log("启用notify失败", res);
        },
      });
    },
    //监听设备返回数据的接收
    onBLECharacteristicValueChange() {
      var that = this;
      uni.onBLECharacteristicValueChange((res) => {
        console.log(res, "返回数据");

        // 结果里有个value值，该值为 ArrayBuffer 类型
        let resHex = that.ab2hex(res.value);
        console.log(resHex, "16进制"); //ArrayBuffer转16进制后的结果
        // 最后将16进制转换为ascii码，就能看到对应的结果 字母 数字
        let result = that.hexToStr(resHex);
        console.log(result, "16进制转成ASCII码"); //16进制 转成 ASCII码 汉字
      });
    },
    ab2hex(buffer) {
      //接收转换
      // ArrayBuffer转16进度字符串示例
      const hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        function (bit) {
          return ("00" + bit.toString(16)).slice(-2);
        }
      );
      return hexArr.join("");
      console.log(hexArr);
    },
    hexToStr(hex) {
      //转成字符串汉字
      // 去掉字符串首尾空格
      let trimedStr = hex.trim();
      // 判断trimedStr前两个字符是否为0x，如果是则截取从第三个字符及后面所有，否则返回全部字符
      let rawStr =
        trimedStr.substr(0, 2).toLowerCase() === "0x"
          ? trimedStr.substr(2)
          : trimedStr;
      // 得到rawStr的长度
      let len = rawStr.length;
      // 如果长度不能被2整除，那么传入的十六进制值有误，返回空字符
      if (len % 2 !== 0) {
        return "";
      }
      let curCharCode; // 接收每次循环得到的字符
      let resultStr = []; // 存转换后的十进制值数组
      for (let i = 0; i < len; i = i + 2) {
        curCharCode = parseInt(rawStr.substr(i, 2), 16);
        resultStr.push(curCharCode);
      }
      // encoding为空时默认为utf-8
      let bytesView = new Uint8Array(resultStr); // 8 位无符号整数值的类型化数组
      // TextEncoder和TextDecoder对字符串和字节流互转
      // let str = new TextDecoder(encoding).decode(bytesView)因为小程序中没有TextDecoder,经查阅资料，下载https://github.com/inexorabletash/text-encoding并const encoding = require("./text-encoding-master/lib/encoding.js")引入后使用下面方式即可：
      let str = new encoding.TextDecoder("gbk").decode(bytesView);
      return str;
    },
    readBLECharacteristicValue() {
      //读取二进制数据值
      let _this = this;
      uni.readBLECharacteristicValue({
        // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
        deviceId: _this.deviceId,
        // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
        serviceId: _this.serviceId,
        // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
        characteristicId: _this.readId,
        success(res) {
          console.log("readBLECharacteristicValue:", res);
        },
      });
    },
    //字符串转ArrayBuff
    strToArrayBuffer(str) {
      // 首先将字符串转为16进制
      let val = str;
      for (let i = 0; i < str.length; i++) {
        if (val === "") {
          val = str.charCodeAt(i).toString(16);
        } else {
          val += "," + str.charCodeAt(i).toString(16);
        }
      }
      console.log(val);
      // 将16进制转化为ArrayBuffer
      return new Uint8Array(
        val.match(/[\da-f]{2}/gi).map(function (h) {
          return parseInt(h, 16);
        })
      ).buffer;
    },
    //字符串转16进制码
    str_to_hex(str) {
      var hexCharCode = [];
      for (var i = 0; i < str.length; i++) {
        hexCharCode.push(str.charCodeAt(i).toString(16));
      }
      hexCharCode = hexCharCode.join("");
      return hexCharCode;
    },
    writeBLECharacteristicValue() {
      //写入值
      let _this = this;
      //蓝牙设备写入数据时，需要将数据先转换为 ArrayBuffer
      let msg = "hello";
      const buffer = new ArrayBuffer(msg.length);
      const dataView = new DataView(buffer);
      // dataView.setUint8(0, 0)

      for (var i = 0; i < msg.length; i++) {
        //只支持英文 数字
        dataView.setUint8(i, msg.charAt(i).charCodeAt());
      }

      // let _this = this;
      uni.writeBLECharacteristicValue({
        deviceId: _this.deviceId,
        serviceId: _this.serviceId,
        characteristicId: _this.writeId,
        value: buffer, //自定义内容buffer
        success(res) {
          console.log("写入成功", res);
        },
        fail(err) {
          console.log("写入失败", err);
        },
      });
    },
  },
};
</script>

<style>
.content {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

.one {
  width: 690upx;
  height: 80upx;
  line-height: 80upx;
  color: #ffffff;
  margin-top: 20upx;
  background-color: #00aaff;
  text-align: center;
  border-radius: 10upx;
}
</style>
